﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TibcoQueueMonitor.Interfaces;
using TibcoQueueMonitor.Entities;
using TibcoQueueMonitor.TibcoAdminManagers;

namespace TibcoQueueMonitor.OfflineDataGenerator
{
    /// <summary>
    /// 
    /// </summary>
    public class OfflineDataGeneratorManager : IOfflineDataGenerator
    {
        #region Constants
        private const string TokenTestQueue = "TestQueue";

        #endregion //Constants

        #region Private Fields
        private Random _rnd = new Random(DateTime.Now.GetHashCode());
        private int queueCount = 30;
        private int maxCount = 120000;

        #endregion //Private Fields

        #region Public Methods
        /// <summary>
        /// Generates the offline test data.
        /// </summary>
        /// <returns></returns>
        public TibcoAdministrationData GenerateOfflineTestData()
        {
            TibcoAdministrationData data = new TibcoAdministrationData(true);
            data.Connections = new Dictionary<string, TibcoConnection>();
            data.Consumers = new Dictionary<string, TibcoConsumer>();
            data.Queues = new Dictionary<string, TibcoQueue>();

            if(queueCount >= maxCount)
                throw new ArgumentOutOfRangeException("Item count should not exceed maxcount.");

            for (int i = 0; i < queueCount; i++)
            {
                TibcoQueue newQueue = GenerateRandomTibcoQueue(data.Queues);
                data.Queues.Add(newQueue.QueueName, newQueue);

                for (int queueIdx = 0; queueIdx < newQueue.Receivers; queueIdx++)
                {
                    TibcoConnection newConn = GenerateRandomTibcoConnection(data.Connections);
                    data.Connections.Add(newConn.ConnectionID, newConn);

                    TibcoConsumer newConsumer = GenerateRandomTibcoConsumer(data.Consumers, newConn, newQueue);
                    data.Consumers.Add(newConsumer.ConsumerID, newConsumer);
                }
            }

            return data;
        }

        #endregion //Public Methods

        #region Private Methods
        private TibcoQueue GenerateRandomTibcoQueue(Dictionary<string, TibcoQueue> queueIndex)
        {
            TibcoQueue newQueue = new TibcoQueue();
            StringBuilder queueNameBuilder = GetRandomId<TibcoQueue>(TokenTestQueue, queueIndex);

            newQueue.QueueName = queueNameBuilder.ToString();
            newQueue.Receivers = _rnd.Next(0, 5);

            if (newQueue.Receivers == 0)
            {
                newQueue.TotalMessageSizeKB = _rnd.Next(0, maxCount) / 100;
                newQueue.MessageCount = _rnd.Next(1, maxCount);
            }
            else
            {
                newQueue.TotalMessageSizeKB = 0;
                newQueue.MessageCount = 0;
            }   

            return newQueue;
        }

        private TibcoConnection GenerateRandomTibcoConnection(Dictionary<string, TibcoConnection> connectionIndex)
        {
            TibcoConnection newConn = new TibcoConnection();
            StringBuilder connectionIdBuilder = GetRandomId<TibcoConnection>(string.Empty, connectionIndex);

            if (_rnd.Next(0, 2) > 0)
                newConn.ClientType = Constants.ClientTypeCSharpLabel;
            else
                newConn.ClientType = Constants.ClientTypeJavaLabel;

            newConn.ConnectionID = connectionIdBuilder.ToString();
            newConn.FaultTolerant = false;
            newConn.Host = string.Concat("Host", _rnd.Next(1, maxCount));
            newConn.SessionNumber = "1";
            newConn.SSLEnabled = false;
            newConn.Uptime = new TimeSpan(_rnd.Next(0, 5), _rnd.Next(0, 24), _rnd.Next(0, 60), _rnd.Next(0, 60));
            newConn.User = string.Concat("User", _rnd.Next(1, 10));

            return newConn;
        }

        private TibcoConsumer GenerateRandomTibcoConsumer(Dictionary<string, TibcoConsumer> consumerIndex, TibcoConnection conn, TibcoQueue queue)
        {
            TibcoConsumer newConsumer = new TibcoConsumer();
            StringBuilder consumerIdBuilder = GetRandomId<TibcoConsumer>(string.Empty, consumerIndex);

            newConsumer.Active = true;
            newConsumer.ConnectionID = conn.ConnectionID;
            newConsumer.ConsumerID = _rnd.Next(1, maxCount).ToString();
            newConsumer.Queue = queue.QueueName;
            newConsumer.User = conn.User;

            return newConsumer;
        }

        private StringBuilder GetRandomId<T>(string customPrefix, Dictionary<string, T> dataIndex)
        {
            StringBuilder queueNameBuilder;

            do
            {
                int randomId = _rnd.Next(1, maxCount);
                queueNameBuilder = new StringBuilder(customPrefix);
                queueNameBuilder.Append(randomId);
            }
            while (dataIndex.ContainsKey(queueNameBuilder.ToString()));

            return queueNameBuilder;
        }

        private TibcoQueue GetRandomQueue(Dictionary<string, TibcoQueue> queueIndex)
        {
            int queueCount = queueIndex.Count;
            int randomQueueId = _rnd.Next(1, queueCount + 1);
            int idx = 1;
            TibcoQueue queue = null;

            foreach (KeyValuePair<string, TibcoQueue> kvp in queueIndex)
            {
                if (idx == randomQueueId)
                {
                    queue = kvp.Value;
                    break;
                }
                else
                {
                    idx++;
                }
            }

            return queue;
        }

        #endregion//Private Methods
    }
}
